package com.example.demoshiro.shiro;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.example.democommon.contasant.CommonConstant;
import com.example.democommon.tools.Result;
import com.example.demoshiro.exception.CustomException;
import com.example.demoshiro.tools.JsonConvertUtil;
import com.example.demoshiro.tools.JwtUtil;
import com.example.demoshiro.tools.RedisUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Resource;
import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * Jwt过滤器
 * </p>
 *
 * @author ross zhang
 * @version 1.0
 * @PackageName demo-one
 * @Package com.example.demoshiro.shiro
 * @since 2022/4/16 15:57
 */
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter implements Filter {

    /**
     * @param servletRequest, response]
     * @return boolean
     * @description: 执行登录
     * @author rosszhang
     * @date 2022-04-16 16:06
     */
    @Override
    protected boolean executeLogin(ServletRequest servletRequest, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String token = httpServletRequest.getHeader(CommonConstant.X_ACCESS_TOKEN);
        JwtToken jwtToken = new JwtToken(token);
        // 提交给realm进行登入，如果错误他会抛出异常并被捕获
        getSubject(servletRequest, response).login(jwtToken);
        // 如果没有抛出异常则代表登入成功，返回true
        return true;
    }

    /**
     * @param servletRequest, servletResponse, mappedValue
     * @return boolean
     * @description: 执行登录认证
     * @author rosszhang
     * @date 2022-04-16 16:06
     */
    @SneakyThrows
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) {
        HttpServletRequest request = WebUtils.toHttp(servletRequest);
        HttpServletResponse response = WebUtils.toHttp(servletResponse);
        try {
            executeLogin(request, response);
            return true;
        } catch (Exception e) {
            request.getRequestDispatcher("/common/unauthorized/" + CommonConstant.TOKEN_IS_INVALID_MSG).forward(request, response);
            return false;
        }
    }

    @Override
    protected boolean preHandle(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
        response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
        // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
        if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
            response.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(servletRequest, servletResponse);
    }

}
